package org.jeecg.modules.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Path;

/**
 * @description: 二维码工具
 * @author: zwf
 * @create: 2025-06-23 16:01
 **/
public class QRCodeUtil {
    public static BufferedImage generateQRCodeImage(String text, int width, int height) throws WriterException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
        return MatrixToImageWriter.toBufferedImage(bitMatrix);
    }

    public static InputStream generateQRCodeStream(String text, int width, int height)
            throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
        BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);

        // 将 BufferedImage 转换为 InputStream
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", os);
        return new ByteArrayInputStream(os.toByteArray());
    }

    public static InputStream generateQRUrlStream(String url, int width, int height)
            throws WriterException, IOException {
        // 确保URL以http://或https://开头
        if (!url.startsWith("http://") && !url.startsWith("https://")) {
            url = "https://" + url;
        }

        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(url, BarcodeFormat.QR_CODE, width, height);
        BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", os);
        return new ByteArrayInputStream(os.toByteArray());
    }

    public static byte[] generateQRCodeImageBytes(String text, int width, int height) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);

        ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);
        return pngOutputStream.toByteArray();
    }

    public static void generateQRCodeImageFile(String text, int width, int height, String filePath)
            throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);

        Path path = FileSystems.getDefault().getPath(filePath);
        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
    }

    public static InputStream generateQRCodeWithLogo(String text, int width, int height, String logoUrl)
            throws WriterException, IOException {
        // 生成基础二维码
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
        BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix);

        // 从网络加载 Logo
        URL url = new URL(logoUrl);
        BufferedImage logoImage = ImageIO.read(url);

        // 计算 Logo 位置（居中）
        int deltaHeight = height - logoImage.getHeight();
        int deltaWidth = width - logoImage.getWidth();

        // 创建组合图像
        BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = (Graphics2D) combined.getGraphics();

        // 绘制二维码
        g.drawImage(qrImage, 0, 0, null);
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));

        // 绘制 Logo（居中）
        g.drawImage(logoImage,
                (int) Math.round(deltaWidth / 2),
                (int) Math.round(deltaHeight / 2),
                null);

        // 转换为 InputStream
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(combined, "png", os);
        return new ByteArrayInputStream(os.toByteArray());
    }

    public static InputStream generateQRCodeWithLogo(
            String text,
            int width,
            int height,
            String logoUrl,
            double logoRatio) throws WriterException, IOException {

        // 生成基础二维码
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
        BufferedImage qrImage = MatrixToImageWriter.toBufferedImage(bitMatrix);

        // 从网络加载 Logo
        BufferedImage originalLogo = ImageIO.read(new URL(logoUrl));

        // 按比例调整 Logo 大小
        int logoWidth = (int) (width * logoRatio);
        int logoHeight = (int) (height * logoRatio);
        BufferedImage logoImage = new BufferedImage(logoWidth, logoHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D gLogo = logoImage.createGraphics();
        gLogo.drawImage(originalLogo, 0, 0, logoWidth, logoHeight, null);
        gLogo.dispose();

        // 计算 Logo 位置（居中）
        int x = (width - logoWidth) / 2;
        int y = (height - logoHeight) / 2;

        // 创建组合图像
        BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = (Graphics2D) combined.getGraphics();

        // 绘制二维码
        g.drawImage(qrImage, 0, 0, null);
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));

        // 绘制 Logo
        g.drawImage(logoImage, x, y, null);
        g.dispose();

        // 转换为 InputStream
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(combined, "png", os);
        return new ByteArrayInputStream(os.toByteArray());
    }
}
